package com.zycfc.zsf.boot.util.bean;

import com.esotericsoftware.reflectasm.*;
import com.zycfc.zsf.boot.util.text.*;
import java.math.*;
import java.util.*;
import java.lang.reflect.*;
import org.slf4j.*;
import java.util.concurrent.*;

public class BeanUtils extends org.apache.commons.beanutils.BeanUtils
{
    private static final Logger log;
    private static Map<Class<?>, MethodAccess> methodMap;
    private static Map<String, Integer> methodIndexMap;
    private static Map<Class<?>, List<String>> fieldMap;
    private static final byte[] LOCK;
    
    public static boolean propertyExists(final Object bean, final String name) {
        try {
            getProperty(bean, name);
            return true;
        }
        catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException ex3) {
            final ReflectiveOperationException ex2 = null;
            final ReflectiveOperationException e = ex2;
            return false;
        }
        catch (RuntimeException ex) {
            return false;
        }
    }
    
    public static void setPropertyLombok(final Object bean, final String name, final Object value) {
        final Method[] methods = bean.getClass().getMethods();
        final Method method = findMethodByName(methods, "set" + toUpperCaseFirstOne(name));
        try {
            method.invoke(bean, value);
        }
        catch (Exception e) {
            BeanUtils.log.error("setPropertyLombok exception", (Throwable)e);
        }
    }
    
    private static Method findMethodByName(final Method[] methods, final String name) {
        for (int j = 0; j < methods.length; ++j) {
            if (methods[j].getName().equals(name)) {
                return methods[j];
            }
        }
        return null;
    }
    
    public static void copyPropertiesExcludeId(final Object destObj, final Object sourceObj) {
        copyPropertiesExclude(destObj, sourceObj, "id");
    }
    
    public static <T> T copyPropertiesExcludeId(final Class<T> destClazz, final Object sourceObj) {
        T descObj = null;
        try {
            descObj = destClazz.newInstance();
            copyPropertiesExclude(descObj, sourceObj, "id");
        }
        catch (InstantiationException e) {
            BeanUtils.log.error("InstantiationException", (Throwable)e);
        }
        catch (IllegalAccessException e2) {
            BeanUtils.log.error("IllegalAccessException", (Throwable)e2);
        }
        catch (IllegalArgumentException e3) {
            BeanUtils.log.error("IllegalArgumentException", (Throwable)e3);
        }
        catch (SecurityException e4) {
            BeanUtils.log.error("SecurityException", (Throwable)e4);
        }
        return descObj;
    }
    
    public static <T> T copyPropertiesExclude(final Class<T> destClazz, final Object sourceObj, final String... properties) {
        T descObj = null;
        try {
            descObj = destClazz.newInstance();
            copyPropertiesExclude(descObj, sourceObj, properties);
        }
        catch (InstantiationException e) {
            BeanUtils.log.error("InstantiationException", (Throwable)e);
        }
        catch (IllegalAccessException e2) {
            BeanUtils.log.error("IllegalAccessException", (Throwable)e2);
        }
        catch (IllegalArgumentException e3) {
            BeanUtils.log.error("IllegalArgumentException", (Throwable)e3);
        }
        catch (SecurityException e4) {
            BeanUtils.log.error("SecurityException", (Throwable)e4);
        }
        return descObj;
    }
    
    public static void copyPropertiesExclude(final Object desc, final Object orgi, final String... properties) {
        final List<String> list = new ArrayList<String>(properties.length);
        for (final String property : properties) {
            list.add(toUpperCaseFirstOne(property));
        }
        copy(desc, orgi, desc.getClass(), orgi.getClass(), true, list);
    }
    
    public static <T> T copyProperties(final Class<T> destClazz, final Object sourceObj) {
        return copyProperties(destClazz, sourceObj, null);
    }
    
    public static <O, T> List<T> copyList(final Class<T> destClazz, final List<O> sourceObjList) {
        if (CheckUtil.isEmpty(sourceObjList)) {
            return null;
        }
        final List<T> resultList = new ArrayList<T>();
        final Object[] t = new Object[1];
        final List<Object> list = new ArrayList<>();
        sourceObjList.forEach(o -> {
            t[0] = copyProperties(destClazz, o);
            list.add(t[0]);
            return;
        });
        return resultList;
    }
    
    public static <T> T copyProperties(final Class<T> destClazz, final Object sourceObj, final Map<String, String> propertyMap) {
        T descObj = null;
        try {
            descObj = destClazz.newInstance();
            copyProperties(descObj, sourceObj, propertyMap);
        }
        catch (InstantiationException e) {
            BeanUtils.log.error("InstantiationException", (Throwable)e);
        }
        catch (IllegalAccessException e2) {
            BeanUtils.log.error("IllegalAccessException", (Throwable)e2);
        }
        catch (IllegalArgumentException e3) {
            BeanUtils.log.error("", (Throwable)e3);
        }
        catch (SecurityException e4) {
            BeanUtils.log.error("IllegalArgumentException", (Throwable)e4);
        }
        return descObj;
    }
    
    public static void copyProperties(final Object desc, final Object orgi) {
        copy(desc, orgi, desc.getClass(), orgi.getClass(), false, null, null);
    }
    
    public static void copyProperties(final Object desc, final Object orgi, final Map<String, String> params) {
        copy(desc, orgi, desc.getClass(), orgi.getClass(), false, null, params);
    }
    
    private static void copy(final Object desc, final Object orgi, final Class<?> descClass, final Class<?> origClass, final boolean flag, final List<String> properties) {
        copy(desc, orgi, descClass, origClass, flag, properties, null);
    }
    
    private static void copy(final Object destObj, final Object sourceObj, final Class<?> destClass, final Class<?> sourceClass, final boolean flag, final List<String> properties, final Map<String, String> params) {
        MethodAccess destMethodAccess = BeanUtils.methodMap.get(destClass);
        if (destMethodAccess == null) {
            destMethodAccess = cache(destClass);
        }
        MethodAccess orgiMethodAccess = BeanUtils.methodMap.get(sourceClass);
        if (orgiMethodAccess == null) {
            orgiMethodAccess = cache(sourceClass);
        }
        final List<String> fieldList = BeanUtils.fieldMap.get(sourceClass);
        for (String field : fieldList) {
            boolean booleanflag = false;
            String getKey;
            if (field.startsWith("boolean|")) {
                booleanflag = true;
                field = field.substring(field.indexOf("|") + 1, field.length());
                getKey = sourceClass.getName() + ".is" + field;
            }
            else {
                getKey = sourceClass.getName() + ".get" + field;
            }
            if (flag && properties.contains(field)) {
                continue;
            }
            String destField = null;
            if (params != null) {
                destField = params.get(toLowerCaseFirstOne(field));
                destField = (StringUtils.isEmpty(destField) ? field : toUpperCaseFirstOne(destField));
            }
            else {
                destField = field;
            }
            final String setkey = destClass.getName() + ".set" + destField;
            final Integer setIndex = BeanUtils.methodIndexMap.get(setkey);
            if (setIndex == null) {
                continue;
            }
            final int getIndex = BeanUtils.methodIndexMap.get(getKey);
            final Object sourceVal = orgiMethodAccess.invoke(sourceObj, getIndex, new Object[0]);
            if (sourceVal == null) {
                continue;
            }
            if (isPrimitive(sourceVal) || String.class.equals(sourceVal.getClass()) || sourceVal instanceof List || BigDecimal.class.equals(sourceVal.getClass()) || BigInteger.class.equals(sourceVal.getClass()) || Date.class.equals(sourceVal.getClass())) {
                destMethodAccess.invoke(destObj, (int)setIndex, new Object[] { sourceVal });
            }
            else if (!(sourceVal instanceof List)) {
                try {
                    Method method;
                    if (booleanflag) {
                        method = findMethodByName(destClass.getMethods(), "is" + destField);
                    }
                    else {
                        method = findMethodByName(destClass.getMethods(), "get" + destField);
                    }
                    final Type type = method.getGenericReturnType();
                    final Class<?> clzz = (Class<?>)type;
                    final Object destValObj = copyProperties(clzz, sourceVal);
                    destMethodAccess.invoke(destObj, (int)setIndex, new Object[] { destValObj });
                }
                catch (Exception e) {
                    BeanUtils.log.error("\u64cd\u4f5c\u5f02\u5e38", (Throwable)e);
                }
            }
            try {
                if (destObj == null) {
                    continue;
                }
                if (booleanflag) {
                    continue;
                }
                final Method method = findMethodByName(destClass.getMethods(), "get" + destField);
                final Object val = method.getReturnType().cast(method.invoke(destObj, new Object[0]));
                if (!(val instanceof List)) {
                    continue;
                }
                final Type type2 = method.getGenericReturnType();
                if ("java.util.List".equals(type2.getTypeName())) {
                    continue;
                }
                Class<?> clzz2 = null;
                if (type2 instanceof ParameterizedType) {
                    final ParameterizedType pt = (ParameterizedType)type2;
                    final Type typeTemp = pt.getActualTypeArguments()[0];
                    if ("?".equals(typeTemp.getTypeName())) {
                        continue;
                    }
                    clzz2 = (Class<?>)typeTemp;
                    if (isWrapClass(clzz2) || String.class.equals(clzz2) || BigDecimal.class.equals(clzz2) || Date.class.equals(clzz2)) {
                        continue;
                    }
                }
                final List<?> valList = (List<?>)val;
                final List<Object> listb = new ArrayList<Object>();
                for (final Object valObj : valList) {
                    final Object destValObj2 = copyProperties(clzz2, valObj);
                    listb.add(destValObj2);
                }
                destMethodAccess.invoke(destObj, (int)setIndex, new Object[] { listb });
            }
            catch (Exception e) {
                BeanUtils.log.error("\u64cd\u4f5c\u5f02\u5e38", (Throwable)e);
            }
        }
    }
    
    private static boolean isPrimitive(final Object obj) {
        try {
            return ((Class)obj.getClass().getField("TYPE").get(null)).isPrimitive();
        }
        catch (Exception e) {
            return false;
        }
    }
    
    private static boolean isWrapClass(final Class clz) {
        try {
            return ((Class)clz.getField("TYPE").get(null)).isPrimitive();
        }
        catch (Exception e) {
            return false;
        }
    }
    
    private static String toUpperCaseFirstOne(final String s) {
        if (Character.isUpperCase(s.charAt(0))) {
            return s;
        }
        return Character.toUpperCase(s.charAt(0)) + s.substring(1);
    }
    
    public static String toLowerCaseFirstOne(final String s) {
        if (Character.isLowerCase(s.charAt(0))) {
            return s;
        }
        return Character.toLowerCase(s.charAt(0)) + s.substring(1);
    }
    
    public static List<Field> getAllFields(final Class<?> orgiClass) {
        final List<Field> fieldList = new ArrayList<Field>();
        for (Class<?> tempClass = orgiClass; tempClass != null && !tempClass.getName().toLowerCase().equals("java.lang.object"); tempClass = tempClass.getSuperclass()) {
            fieldList.addAll(Arrays.asList(tempClass.getDeclaredFields()));
        }
        return fieldList;
    }
    
    private static MethodAccess cache(final Class<?> orgiClass) {
        synchronized (BeanUtils.LOCK) {
            MethodAccess methodAccess = BeanUtils.methodMap.get(orgiClass);
            if (methodAccess != null) {
                return methodAccess;
            }
            methodAccess = MethodAccess.get((Class)orgiClass);
            final List<Field> fields = getAllFields(orgiClass);
            final List<String> fieldList = new ArrayList<String>();
            for (final Field field : fields) {
                if (!Modifier.isStatic(field.getModifiers()) && !Modifier.isTransient(field.getModifiers())) {
                    final String fieldName = StringUtils.capitalize(field.getName());
                    final Class<?> type = field.getType();
                    if (Boolean.TYPE.equals(type)) {
                        final int getIndex = methodAccess.getIndex("is" + fieldName);
                        BeanUtils.methodIndexMap.put(orgiClass.getName() + ".is" + fieldName, getIndex);
                        fieldList.add("boolean|" + fieldName);
                    }
                    else {
                        final int getIndex = methodAccess.getIndex("get" + fieldName);
                        BeanUtils.methodIndexMap.put(orgiClass.getName() + ".get" + fieldName, getIndex);
                        fieldList.add(fieldName);
                    }
                    final int setIndex = methodAccess.getIndex("set" + fieldName);
                    BeanUtils.methodIndexMap.put(orgiClass.getName() + ".set" + fieldName, setIndex);
                }
            }
            BeanUtils.fieldMap.put(orgiClass, fieldList);
            BeanUtils.methodMap.put(orgiClass, methodAccess);
            return methodAccess;
        }
    }
    
    static {
        log = LoggerFactory.getLogger((Class)BeanUtils.class);
        BeanUtils.methodMap = new ConcurrentHashMap<Class<?>, MethodAccess>();
        BeanUtils.methodIndexMap = new ConcurrentHashMap<String, Integer>();
        BeanUtils.fieldMap = new ConcurrentHashMap<Class<?>, List<String>>();
        LOCK = new byte[0];
    }
}
